#ifndef __DICCACOTADO_H__
#define __DICCACOTADO_H__


#include "../aed2/ConjAcotado.h"

namespace aed2 {

	template<class T>
	/* Esta clase implementa el modulo diccionario acotado, el cual esta acotado superiormente.
	Las claves son Nat y sus valores posibles estan acotados, siendo estos menores al valor n pasado a la operacion
	Vacio(N), cuya complejidad es O(n). Tanto la definicion como la obtencion de significados se pueden hacer en O(1).
	Este modulo no ofrece los servicios Borrar y Claves.*/
	//Se provee de un iterador para recorrer los elementos del diccionario. 


	class DiccAcotado{
	public:
		class const_Iterador;
		
		struct const_Elem;

		DiccAcotado(Nat n);

		~DiccAcotado();

		const_Iterador Definir(Nat c, const T &s);

		bool Definido(Nat c)const;

		T& Obtener(Nat c);

		const T& Obtener(Nat c) const;

		Nat Cota() const;
		
		const_Iterador CrearIt() const {
			return const_Iterador(*this);
		}

		ConjAcotado::const_Iterador Claves() const {
			return definidas->CrearIt();
		}

		DiccAcotado(const DiccAcotado<T> & d) {
			significados = new Arreglo<T>(*(d.significados));
			definidas = new ConjAcotado(*(d.definidas));
		}

		class const_Iterador{
		   public:
			
				const_Iterador(const typename DiccAcotado<T>::const_Iterador& otro) : itC(otro.itC), significados(otro.significados) {}
				const_Iterador& operator=(const typename DiccAcotado<T>::const_Iterador& otro) 
				{itC = otro.itC; significados = otro.significados; return *this;}
				const_Iterador() {}

				bool operator==(const typename DiccAcotado<T>::const_Iterador& otro) const{return itC == otro.itC;}

				bool HaySiguiente() const{
				 return itC.HaySiguiente();
				}

				bool HayAnterior() const { 
					return itC.HayAnterior();
				}

				Nat SiguienteClave() const { 
					assert(HaySiguiente());    
					return itC.Siguiente();
				}
				
				const T& SiguienteSignificado() const{
					assert(HaySiguiente());
					return (*significados)[itC.Siguiente()];
				}

				Nat AnteriorClave() const{
					assert(HayAnterior());   
					return itC.Anterior();
				}

				const T& AnteriorSignificado() const{
					assert(HayAnterior());
					return (*significados)[itC.Anterior()];
				}
				
				const_Elem Siguiente() const{
					assert(HaySiguiente());
					return const_Elem(SiguienteClave(), SiguienteSignificado());
				}
				
				const_Elem Anterior() const{
					assert(HayAnterior());
					return const_Elem(AnteriorClave(), AnteriorSignificado());
				}
					
				void Avanzar(){
					assert(itC.HaySiguiente());
					itC.Avanzar(); 
				}

				void Retroceder(){
					assert(HayAnterior());
					itC.Retroceder();
				}
		   
		private:
				const_Iterador(const DiccAcotado<T> & d) : itC(d.definidas->CrearIt()), significados(d.significados) {}
				friend typename DiccAcotado<T>::const_Iterador DiccAcotado<T>::CrearIt() const;
				friend typename ConjAcotado::const_Iterador DiccAcotado<T>::Claves() const;
				ConjAcotado::const_Iterador itC;
				Arreglo<T> *significados;
				
			};

			struct const_Elem {
					Nat clave;
					const T& significado;
					const_Elem(Nat c, const T& s) : clave(c), significado(s) {}
								
					friend std::ostream& operator<<(std::ostream& os, const DiccAcotado<T>::const_Elem& e) {
						return os << e.clave << ":" << e.significado;
					}
				private:
					typename DiccAcotado<T>::const_Elem& operator=(const DiccAcotado<T>::const_Elem&);
			};

		DiccAcotado<T>& operator=(const DiccAcotado<T>& d2){
			significados= new Arreglo<T>(d2.significados);
			definidas= new ConjAcotado(d2.definidas);
			return *this;
		} 		//Asignacion (copy) : guarda una copia nueva del diccionario en this

	private:
	
		Arreglo<T> *significados;
		ConjAcotado *definidas; 
	};


	template<class T>
	std::ostream& operator<<(std::ostream& os, const DiccAcotado<T>& c){
		return Mostrar(os, c, '{', '}');
	}

	//Implementaci�n


	//Constructor
	//genera un diccionario vacio que acepta claves naturales en el intervalo [0,n-1]; (Operaci�n Vacia(n))
	template<class T>
	DiccAcotado<T>::DiccAcotado(Nat n){
		this->significados = new Arreglo<T>(n);
		this->definidas = new ConjAcotado(0,n-1);
	}

	//Destructor
	template<class T>
	DiccAcotado<T>::~DiccAcotado(){
		delete significados;
		delete definidas;
	}

	//Define una nueva clave c con el valor s si la clave esta por debajo de la cota superior
	template<class T>
	typename DiccAcotado<T>::const_Iterador DiccAcotado<T>::Definir(Nat c, const T & s){

		assert( c < significados->Tamanho());

		this->definidas->Agregar(c);
		this->significados->Definir(c,s);
		return CrearIt();	
	}
		
	//Devuelve true si hay un valor definido para la clave c			
	template<class T>
	bool DiccAcotado<T>::Definido(Nat c)const{
		return this->definidas->Pertenece(c);
	}

	//Devuelve el valor definido para la clave c
	//Resultado modificable sii diccionario lo es	
	template<class T>	
	const T& DiccAcotado<T>::Obtener(Nat c) const {
		assert(Definido(c));
		return (*this->significados)[c];
	}

	//Devuelve el valor definido para la clave c
	//Resultado modificable sii diccionario lo es
	template<class T>
	T& DiccAcotado<T>::Obtener(Nat c){
		assert(Definido(c));
		return (*this->significados)[c];
	}

}
#endif /* __DICCACOTADO_H__*/
